package com.biz.primus.ms.base.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author yanweijin
 * @date 2017/9/11
 */
public class RedisIdxFactoryImpl implements IdxFactory{

	private ShardedJedisPool jedisPool;

	private Long workerId = null;

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	private static final String randomMark = UUID.randomUUID().toString();

	private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();


	public RedisIdxFactoryImpl(ShardedJedisPool jedisPool) {
		Assert.notNull(jedisPool,"必须提供一个非空的shardedJedisPool");
		this.jedisPool = jedisPool;
	}

	@PostConstruct
	void initWorkerId() {
		String keyPrefix = "system:soa:idx:";
		try(ShardedJedis jedis = jedisPool.getResource()) {
			for (long i = 0; i < MAX_WORKER_ID; i++) {
				String workIdKey = keyPrefix + i;
				Long success = jedis.setnx(workIdKey, randomMark);
				if(success==1){
					jedis.expire(workIdKey,120);
					this.workerId = i;
					logger.info("使用RedisIdxFactoryImpl生成workerId={}",workerId);
					beginCheckTask(workIdKey);
					return;
				}
			}
		}
		throw new IllegalStateException("没有可分配的workerId");
	}

	@PreDestroy
	void destroy(){
		executorService.shutdown();
	}

	@Override
	public synchronized long getWorkerIdx() {
		if(workerId!=null)return workerId;
		initWorkerId();
		return workerId;
	}
	/**
	 * 开启心跳检查
	 * @param workIdKey
	 */
	private void beginCheckTask(final String workIdKey) {
		//10秒检查一次
		executorService.scheduleAtFixedRate(() -> {
			try (ShardedJedis jedis = jedisPool.getResource()) {
				String mark = jedis.get(workIdKey);
				if (Objects.equals(mark, randomMark)) {
					jedis.expire(workIdKey, 120);
				} else {
					logger.error("**【严重】** workerId可能重复重复,当前应用randomMark为{},获取的mark为{}", randomMark, mark);
				}
			} catch (Exception e) {
				logger.error("**【严重】** workerId心跳检查中断,可能导致workerId重复");
			}
		}, 10000, 10, TimeUnit.SECONDS);
	}

}


